home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / textual / tex / files / !tex / TeXsource / commontex / c / page < prev    next >
Encoding:
Text File  |  1988-04-18  |  32.9 KB  |  896 lines

  1. /*
  2.  *    Copyright 1986, 1987 Pat Joseph Monardo. All rights reserved.
  3.  *    Copying of this file is granted according to the provisions 
  4.  *    specified in the file COPYING which must accompany this file.
  5.  */
  6.  
  7.  
  8. /*
  9.  *              page.c
  10.  */
  11.  
  12. #include "tex.h"
  13. #include "heap.h"
  14. #include "arith.h"
  15. #include "str.h"
  16. #include "token.h"
  17. #include "tokenstack.h"
  18. #include "tokenlists.h"
  19. #include "eq.h"
  20. #include "eqstack.h"
  21. #include "evalstack.h"
  22. #include "scan.h"
  23. #include "expand.h"
  24. #include "box.h"
  25. #include "pack.h"
  26. #include "par.h"
  27. #include "math.h"
  28. #include "dvi.h"
  29. #include "print.h"
  30. #include "error.h"
  31. #include "page.h"
  32.  
  33. scal    best_height_plus_depth;
  34. ptr             best_page_break;
  35. scal    best_size;
  36. scal    cur_page_depth;
  37. val             insert_penalties;
  38. ptr             last_glue = MAX_HALFWORD;
  39. scal    last_kern;
  40. val             last_penalty;
  41. val             least_page_cost;
  42. bool    output_active;
  43. int             page_contents;
  44. scal    page_max_depth;
  45. ptr             page_tail;
  46. scal    page_so_far[8];
  47.  
  48. #define set_page_so_far_zero(P) (page_so_far[P] = 0)
  49. #define set_height_zero(H)              (active_height[H] = 0)
  50.  
  51. ptr
  52. prune_page_top (p)
  53.         ptr             p;
  54. {
  55.         ptr             q;
  56.         ptr             prev_p;
  57.  
  58.         prev_p = temp_head;
  59.         link(temp_head) = p;
  60.         while (p != NULL) {
  61.                 switch (type(p))
  62.                 {
  63.                 case HLIST_NODE:
  64.                 case VLIST_NODE:
  65.                 case RULE_NODE:
  66.                         q = new_skip_param(SPLIT_TOP_SKIP_CODE);
  67.                         link(prev_p) = q;
  68.                         link(q) = p;
  69.                         if (width(temp_ptr) > height(p))
  70.                                 width(temp_ptr) -= height(p);
  71.                         else width(temp_ptr) = 0;
  72.                         p = NULL;
  73.                         break;
  74.  
  75.                 case WHATSIT_NODE:
  76.                 case MARK_NODE:
  77.                 case INS_NODE:
  78.                         prev_p = p;
  79.                         p = link(prev_p);
  80.                         break;
  81.                 
  82.                 case GLUE_NODE:
  83.                 case KERN_NODE:
  84.                 case PENALTY_NODE:
  85.                         q = p;
  86.                         p = link(q);
  87.                         link(q) = NULL;
  88.                         link(prev_p) = p;
  89.                         flush_node_list(q);
  90.                         break;
  91.  
  92.                 default:
  93.                         confusion("pruning");
  94.                         break;
  95.                 }
  96.         }
  97.         return (link(temp_head));
  98. }
  99.  
  100. ptr
  101. vert_break (p, h, d)
  102.         ptr             p;
  103.         scal    h;
  104.         scal    d;
  105. {
  106.         val             b;
  107.         ptr             q;
  108.         ptr             r;
  109.         int             t;
  110.         val             pi;
  111.         ptr             prev_p;
  112.         scal    prev_dp;
  113.         ptr             best_place;
  114.         val             least_cost;
  115.  
  116.         prev_p = p;
  117.         least_cost = AWFUL_BAD;
  118.         do_all_six(set_height_zero);
  119.         prev_dp = 0;
  120.         loop {
  121.                 if (p == NULL)
  122.                         pi = EJECT_PENALTY;
  123.                 else {
  124.                         switch (type(p))
  125.                         {
  126.                         case HLIST_NODE:
  127.                         case VLIST_NODE:
  128.                         case RULE_NODE:
  129.                                 cur_height = cur_height + prev_dp + height(p);
  130.                                 prev_dp = depth(p);
  131.                                 goto not_found;
  132.                                 break;
  133.                         
  134.                         case WHATSIT_NODE:
  135.                                 goto not_found;
  136.                                 break;
  137.                         
  138.                         case GLUE_NODE:
  139.                                 if (precedes_break(prev_p))
  140.                                         pi = 0;
  141.                                 else goto update_heights;
  142.                                 break;
  143.                         
  144.                         case KERN_NODE:
  145.                                 if (link(p) == NULL)
  146.                                         t = PENALTY_NODE;
  147.                                 else t = type(link(p));
  148.                                 if (t == GLUE_NODE)
  149.                                         pi = 0;
  150.                                 else goto update_heights;
  151.                                 break;
  152.                         
  153.                         case PENALTY_NODE:
  154.                                 pi = penalty(p);
  155.                                 break;
  156.                         
  157.                         case MARK_NODE:
  158.                         case INS_NODE:
  159.                                 goto not_found;
  160.                                 break;
  161.                         
  162.                         default:
  163.                                 confusion("vertbreak");
  164.                                 break;
  165.                         }
  166.                 }
  167.                 if (pi < INF_PENALTY) {
  168.                         if (cur_height < h) {
  169.                                 if (active_height[3] != 0 ||
  170.                                         active_height[4] != 0 ||
  171.                                         active_height[5] != 0)
  172.                                         b = 0;
  173.                                 else b = badness(h - cur_height, active_height[2]);
  174.                         } else if (cur_height - h > active_height[6])
  175.                                 b = AWFUL_BAD;
  176.                         else b = badness(cur_height - h, active_height[6]);
  177.                         if (b < AWFUL_BAD) {
  178.                                 if (pi <= EJECT_PENALTY)
  179.                                         b = pi;
  180.                                 else if (b < INF_BAD)
  181.                                         b += pi;
  182.                                 else b = DEPLORABLE;
  183.                         }
  184.                         if (b <= least_cost) {
  185.                                 best_place = p;
  186.                                 least_cost = b;
  187.                                 best_height_plus_depth = cur_height + prev_dp;
  188.                         }
  189.                         if (b == AWFUL_BAD || pi <= EJECT_PENALTY)
  190.                                 return best_place;
  191.                 }
  192.                 if (type(p) < GLUE_NODE || type(p) > KERN_NODE)
  193.                         goto not_found;
  194.  
  195.         update_heights:
  196.                 if (type(p) == KERN_NODE)
  197.                         q = p;
  198.                 else {
  199.                         q = glue_ptr(p);
  200.                         active_height[2 + stretch_order(q)] += stretch(q);
  201.                         active_height[6] += shrink(q);
  202.                         if (shrink_order(q) != NORMAL && shrink(q) != 0) {
  203.                                 print_err("Infinite glue shrinkage found in box being split");
  204.                                 help_inf_shrink_box();
  205.                                 error();
  206.                                 r = new_spec(q);
  207.                                 delete_glue_ref(q);
  208.                                 shrink_order(r) = NORMAL;
  209.                                 glue_ptr(p) = r;
  210.                         }
  211.                 }
  212.                 cur_height = cur_height + prev_dp + width(q);
  213.                 prev_dp = 0;
  214.  
  215.         not_found:
  216.                 if (prev_dp > d) {
  217.                         cur_height = cur_height + prev_dp - d;
  218.                         prev_dp = d;
  219.                 }
  220.                 prev_p = p;
  221.                 p = link(prev_p);
  222.         }
  223. }
  224.  
  225. ptr
  226. vsplit (n, h)
  227.         int             n;
  228.         scal    h;
  229. {
  230.         ptr             p;
  231.         ptr             q;
  232.         ptr             v;
  233.  
  234.         v = box(n);
  235.         if (split_first_mark != NULL) {
  236.                 delete_token_ref(split_first_mark);
  237.                 split_first_mark = NULL;
  238.                 delete_token_ref(split_bot_mark);
  239.                 split_bot_mark = NULL;
  240.         }
  241.         if (v == NULL)
  242.                 return NULL;
  243.         if (type(v) != VLIST_NODE) {
  244.                 print_err("");
  245.                 print_esc("vsplit");
  246.                 print(" needs a ");
  247.                 print_esc("vbox");
  248.                 help_vsplit_vbox();
  249.                 error();
  250.                 return NULL;
  251.         }
  252.         q = vert_break(list_ptr(v), h, split_max_depth);
  253.         p = list_ptr(v);
  254.         if (p == q)
  255.                 list_ptr(v) = NULL;
  256.         else {
  257.                 loop {
  258.                         if (type(p) == MARK_NODE) {
  259.                                 if (split_first_mark == NULL) {
  260.                                         split_first_mark = mark_ptr(p);
  261.                                         split_bot_mark = split_first_mark;
  262.                                         token_ref_count(split_first_mark) += 2;
  263.                                 } else {
  264.                                         delete_token_ref(split_bot_mark);
  265.                                         split_bot_mark = mark_ptr(p);
  266.                                         add_token_ref(split_bot_mark);
  267.                                 }
  268.                         }
  269.                         if (link(p) == q) {
  270.                                 link(p) = NULL;
  271.                                 break;
  272.                         }
  273.                         p = link(p);
  274.                 }
  275.         }
  276.         q = prune_page_top(q);
  277.         p = list_ptr(v);
  278.         free_node(v, BOX_NODE_SIZE);
  279.         if (q == NULL)
  280.                 box(n) = NULL;
  281.         else box(n) = vpack(q, NATURAL);
  282.         return (vpackage(p, h, EXACTLY, split_max_depth));
  283. }
  284.  
  285. freeze_page_specs (s)
  286.         int             s;
  287. {
  288.         page_contents = s;
  289.         page_goal = vsize;
  290.         page_max_depth = max_depth;
  291.         page_depth = 0;
  292.         do_all_six(set_page_so_far_zero);
  293.         least_page_cost = AWFUL_BAD;
  294. #ifdef STAT
  295.         if (tracing_pages > 0) {
  296.                 begin_diagnostic();
  297.                 print_nl("%% goal height=");
  298.                 print_scaled(page_goal);
  299.                 print(", max depth=");
  300.                 print_scaled(page_max_depth);
  301.                 end_diagnostic(FALSE);
  302.         }
  303. #endif
  304. }
  305.  
  306. box_error (n)
  307.         int             n;
  308. {
  309.         error();
  310.         begin_diagnostic();
  311.         print_nl("The following box has been deleted:");
  312.         show_box(box(n));
  313.         end_diagnostic(TRUE);
  314.         flush_node_list(box(n));
  315.         box(n) = NULL;
  316. }
  317.  
  318. ensure_vbox (n)
  319.         int             n;
  320. {
  321.         ptr             p;
  322.  
  323.         p = box(n);
  324.         if (p != NULL && type(p) == HLIST_NODE) {
  325.                 print_err("Insertions can only be added to a vbox");
  326.                 help_tut();
  327.                 box_error(n);
  328.         }
  329. }
  330.  
  331. print_plus (s, o)
  332.         int             s;
  333.         char*   o;
  334. {
  335.         if (page_so_far[s] != 0) {
  336.                 print(" plus ");
  337.                 print_scaled(page_so_far[s]);
  338.                 print(o);
  339.         }
  340. }
  341.  
  342. print_totals ()
  343. {
  344.         print_scaled(page_total);
  345.         print_plus(2, "");
  346.         print_plus(3, "fil");
  347.         print_plus(4, "fill");
  348.         print_plus(5, "filll");
  349.         if (page_shrink != 0) {
  350.                 print(" minus ");
  351.                 print_scaled(page_shrink);
  352.         }
  353. }
  354.  
  355. #ifdef STAT
  356. show_split(n, w, q)
  357.         int             n;
  358.         scal    w;
  359.         ptr             q;
  360. {
  361.         begin_diagnostic();
  362.         print_nl("% split");
  363.         print_int(n);
  364.         print(" to ");
  365.         print_scaled(w);
  366.         print_char(',');
  367.         print_scaled(best_height_plus_depth);
  368.         print(" p=");
  369.         if (q == NULL)
  370.                 print_int(EJECT_PENALTY);
  371.         else if (type(q) == PENALTY_NODE)
  372.                 print_val(penalty(q));
  373.         else print_char('0');
  374.         end_diagnostic(FALSE);
  375. }
  376.  
  377. show_page_stats (b, p, c)
  378.         val             b;
  379.         val             p;
  380.         val             c;
  381. {
  382.         if (tracing_pages > 0) {
  383.                 begin_diagnostic();
  384.                 print_nl("%");
  385.                 print(" t=");
  386.                 print_totals();
  387.                 print(" g=");
  388.                 print_scaled(page_goal);
  389.                 print(" b=");
  390.                 if (b == AWFUL_BAD)
  391.                         print_char('*');
  392.                 else print_val(b);
  393.                 print(" p=");
  394.                 print_val(p);
  395.                 print(" c=");
  396.                 if (c == AWFUL_BAD)
  397.                         print_char('*');
  398.                 else print_val(c);
  399.                 if (c <= least_page_cost)
  400.                         print_char('#');
  401.                 end_diagnostic(FALSE);
  402.         }
  403. }
  404. #endif
  405.  
  406. build_page ()
  407. {
  408.         val             b;
  409.         val             c;
  410.         scal    h;
  411.         int             n;
  412.         ptr             p;
  413.         ptr             q;
  414.         ptr             r;
  415.         scal    w;
  416.         val             pi;
  417.         scal    delta;
  418.         
  419.         if (link(contrib_head) == NULL || output_active)
  420.                 return;
  421.         do { 
  422.                 p = link(contrib_head);
  423.                 if (last_glue != MAX_HALFWORD)
  424.                         delete_glue_ref(last_glue);
  425.                 last_penalty = 0;
  426.                 last_kern = 0;
  427.                 if (type(p) == GLUE_NODE) {
  428.                         last_glue = glue_ptr(p);
  429.                         add_glue_ref(last_glue);
  430.                 } else {
  431.                         last_glue = MAX_HALFWORD;
  432.                         if (type(p) == PENALTY_NODE)
  433.                                 last_penalty = penalty(p);
  434.                         else if (type(p) == KERN_NODE)
  435.                                 last_kern = width(p);
  436.                 }
  437.                 switch (type(p))
  438.                 {
  439.                 case HLIST_NODE:
  440.                 case VLIST_NODE:
  441.                 case RULE_NODE:
  442.                         if (page_contents < BOX_THERE) {
  443.                                 if (page_contents == EMPTY)
  444.                                         freeze_page_specs(BOX_THERE);
  445.                                 else page_contents = BOX_THERE;
  446.                                 q = new_skip_param(TOP_SKIP_CODE);
  447.                                 link(q) = p;
  448.                                 if (width(temp_ptr) > height(p))
  449.                                         width(temp_ptr) -= height(p);
  450.                                 else width(temp_ptr) = 0;
  451.                                 link(q) = p;
  452.                                 link(contrib_head) = q;
  453.                                 continue;
  454.                         } else {
  455.                                 page_total = page_total + page_depth + height(p);
  456.                                 page_depth = depth(p);
  457.                                 goto contribute;
  458.                         }
  459.                         break;
  460.                 
  461.                 case WHATSIT_NODE:
  462.                         goto contribute;
  463.                         break;
  464.                 
  465.                 case GLUE_NODE:
  466.                         if (page_contents < BOX_THERE)
  467.                                 goto done;
  468.                         else if (precedes_break(page_tail))
  469.                                 pi = 0;
  470.                         else goto update_heights;
  471.                         break;
  472.                 
  473.                 case KERN_NODE:
  474.                         if (page_contents < BOX_THERE)
  475.                                 goto done;
  476.                         else if (link(p) == NULL)
  477.                                 return;
  478.                         else if (type(link(p)) == GLUE_NODE)
  479.                                 pi = 0;
  480.                         else goto update_heights;
  481.                         break;
  482.                 
  483.                 case PENALTY_NODE:
  484.                         if (page_contents < BOX_THERE)
  485.                                 goto done;
  486.                         else pi = penalty(p);
  487.                         break;
  488.  
  489.                 case MARK_NODE:
  490.                         goto contribute;
  491.                         break;
  492.  
  493.                 case INS_NODE:
  494.                         if (page_contents == EMPTY)
  495.                                 freeze_page_specs(INSERTS_ONLY);
  496.                         n = subtype(p);
  497.                         r = page_ins_head;
  498.                         while (n >= subtype(link(r)))
  499.                                 r = link(r);
  500.                         if (subtype(r) != n) {
  501.                                 q = get_node(PAGE_INS_NODE_SIZE);
  502.                                 link(q) = link(r);
  503.                                 link(r) = q;
  504.                                 r = q;
  505.                                 subtype(r) = qi(n);
  506.                                 type(r) = INSERTING;
  507.                                 ensure_vbox(n);
  508.                                 if (box(n) == NULL)
  509.                                         height(r) = 0;
  510.                                 else height(r) = height(box(n)) + depth(box(n));
  511.                                 best_ins_ptr(r) = NULL;
  512.                                 q = skip(n);
  513.                                 if (count(n) == 1000)
  514.                                         h = height(r);
  515.                                 else h = x_over_n(height(r), 1000L) * count(n);
  516.                                 page_goal = page_goal - h - width(q);
  517.                                 page_so_far[2 + stretch_order(q)] += stretch(q);
  518.                                 page_shrink += shrink(q);
  519.                                 if (shrink_order(q) != NORMAL && shrink(q) != 0) {
  520.                                         print_err("Infinite glue shrinkage inserted from ");
  521.                                         print_esc("skip");
  522.                                         print_int(n);
  523.                                         help_inf_shrink_ins();
  524.                                         error();
  525.                                 }
  526.                         }
  527.                         if (type(r) == SPLIT_UP)
  528.                                 insert_penalties += float_cost(p);
  529.                         else {
  530.                                 last_ins_ptr(r) = p;
  531.                                 delta = page_goal - page_total - page_depth + page_shrink;
  532.                                 if (count(n) == 1000)
  533.                                         h = height(p);
  534.                                 else h = x_over_n(height(p), 1000L) * count(n);
  535.                                 if ((h <= 0 || h <= delta) &&
  536.                                         height(p) + height(r) <= dimen(n)) {
  537.                                         page_goal -= h;
  538.                                         height(r) += height(p);
  539.                                 } else {
  540.                                         if (count(n) <= 0)
  541.                                                 w = MAX_DIMEN;
  542.                                         else {
  543.                                                 w = page_goal - page_total - page_depth;
  544.                                                 if (count(n) != 1000) 
  545.                                                         w = x_over_n(w, count(n)) * 1000;
  546.                                         }
  547.                                         if (w > dimen(n) - height(r))
  548.                                                 w = dimen(n) - height(r);
  549.                                         q = vert_break(ins_ptr(p), w, depth(p));
  550.                                         height(r) += best_height_plus_depth;
  551. #ifdef STAT
  552.                                         show_split(n, w, q);
  553. #endif
  554.                                         if (count(n) != 1000)
  555.                                                 best_height_plus_depth =
  556.                                                         x_over_n(best_height_plus_depth, 1000L) * count(n);
  557.                                         page_goal -= best_height_plus_depth;
  558.                                         type(r) = SPLIT_UP;
  559.                                         broken_ptr(r) = q;
  560.                                         broken_ins(r) = p;
  561.                                         if (q == NULL)
  562.                                                 insert_penalties += EJECT_PENALTY;
  563.                                         else if (type(q) == PENALTY_NODE)
  564.                                                 insert_penalties += penalty(q);
  565.                                 }
  566.                         }
  567.                         goto contribute;
  568.                         break;
  569.                 
  570.                 default:
  571.                         confusion("page");
  572.                         break;
  573.                 }
  574.                 if (pi < INF_PENALTY) {
  575.                         if (page_total < page_goal) {
  576.                                 if (page_so_far[3] != 0 ||
  577.                                         page_so_far[4] != 0 ||
  578.                                         page_so_far[5] != 0)
  579.                                         b = 0;
  580.                                 else b = badness(page_goal - page_total, page_so_far[2]);
  581.                         } else if (page_total - page_goal > page_shrink)
  582.                                 b = AWFUL_BAD;
  583.                         else b = badness(page_total - page_goal, page_shrink);
  584.                         if (b < AWFUL_BAD) {
  585.                                 if (pi <= EJECT_PENALTY)
  586.                                         c = pi;
  587.                                 else if (b < INF_BAD)
  588.                                         c = b + pi + insert_penalties;
  589.                                 else c = DEPLORABLE;
  590.                         } else c = b;
  591.                         if (insert_penalties >= 10000)
  592.                                 c = AWFUL_BAD;
  593. #ifdef STAT
  594.                         show_page_stats(b, pi, c);
  595. #endif
  596.                         if (c <= least_page_cost) {
  597.                                 best_page_break = p;
  598.                                 best_size = page_goal;
  599.                                 least_page_cost = c;
  600.                                 r = link(page_ins_head);
  601.                                 while (r != page_ins_head) {
  602.                                         best_ins_ptr(r) = last_ins_ptr(r);
  603.                                         r = link(r);
  604.                                 }
  605.                         }
  606.                         if (c == AWFUL_BAD || pi <= EJECT_PENALTY) {
  607.                                 fire_up(p);
  608.                                 if (output_active) return;
  609.                                 continue;
  610.                         }
  611.                 }
  612.                 if (type(p) < GLUE_NODE || type(p) > KERN_NODE)
  613.                         goto contribute;
  614.                 
  615.         update_heights:
  616.                 if (type(p) == KERN_NODE)
  617.                         q = p;
  618.                 else {
  619.                         q = glue_ptr(p);
  620.                         page_so_far[2 + stretch_order(q)] += stretch(q);
  621.                         page_shrink += shrink(q);
  622.                         if (shrink_order(q) != NORMAL && shrink(q) != 0) {
  623.                                 print_err("Infinite glue shrinkage found on current page");
  624.                                 help_inf_shrink_page();
  625.                                 error();
  626.                                 r = new_spec(q);
  627.                                 shrink_order(r) = NORMAL;
  628.                                 delete_glue_ref(q);
  629.                                 glue_ptr(p) = r;
  630.                         }
  631.                 }
  632.                 page_total = page_total + page_depth + width(q);
  633.                 page_depth = 0;
  634.  
  635.         contribute:
  636.                 if (page_depth > page_max_depth) {
  637.                         page_total = page_total + page_depth - page_max_depth;
  638.                         page_depth = page_max_depth;
  639.                 }
  640.                 link(page_tail) = p;
  641.                 page_tail = p;
  642.                 link(contrib_head) = link(p);
  643.                 link(p) = NULL;
  644.                 continue;
  645.  
  646.         done:
  647.                 link(contrib_head) = link(p);
  648.                 link(p) = NULL;
  649.                 flush_node_list(p);
  650.         } while (link(contrib_head) != NULL);
  651.         if (nest_ptr == 0)
  652.                 tail = contrib_head;
  653.         else contrib_tail = contrib_head;
  654. }
  655.  
  656. fire_up (c)
  657.         ptr             c;
  658. {
  659.         int             n;
  660.         ptr             p;
  661.         ptr             q;
  662.         ptr             r;
  663.         ptr             s;
  664.         bool    wait;
  665.         ptr             prev_p;
  666.         scal    save_vfuzz;
  667.         val             save_vbadness;
  668.         ptr             save_split_top_skip;
  669.  
  670.         if (type(best_page_break) == PENALTY_NODE) {
  671.                 geq_word_define(INT_BASE+OUTPUT_PENALTY_CODE, penalty(best_page_break));
  672.                 penalty(best_page_break) = INF_PENALTY;
  673.         } else geq_word_define(INT_BASE+OUTPUT_PENALTY_CODE, INF_PENALTY);
  674.         if (bot_mark != NULL) {
  675.                 if (top_mark != NULL)
  676.                         delete_token_ref(top_mark);
  677.                 top_mark = bot_mark;
  678.                 add_token_ref(top_mark);
  679.                 delete_token_ref(first_mark);
  680.                 first_mark = NULL;
  681.         }
  682.         if (c == best_page_break)
  683.                 best_page_break = NULL;
  684.         if (box(255) != NULL) {
  685.                 print_err("");
  686.                 print_esc("box");
  687.                 print("255 is not void");
  688.                 help_box_255();
  689.                 box_error(255);
  690.         }
  691.         insert_penalties = 0;
  692.         save_split_top_skip = split_top_skip;
  693.         r = link(page_ins_head);
  694.         while (r != page_ins_head) {
  695.                 if (best_ins_ptr(r) != NULL) {
  696.                         n = qo(subtype(r));
  697.                         ensure_vbox(n);
  698.                         if (box(n) == NULL)
  699.                                 box(n) = new_null_box();
  700.                         p = box(n) + LIST_OFFSET;
  701.                         while (link(p) != NULL)
  702.                                 p = link(p);
  703.                         last_ins_ptr(r) = p;
  704.                 }
  705.                 r = link(r);
  706.         }
  707.         q = hold_head;
  708.         link(q) = NULL;
  709.         prev_p = page_head;
  710.         p = link(prev_p);
  711.         while (p != best_page_break) {
  712.                 if (type(p) == INS_NODE) {
  713.                         r = link(page_ins_head);
  714.                         while (subtype(r) != subtype(p))
  715.                                 r = link(r);
  716.                         if (best_ins_ptr(r) == NULL)
  717.                                 wait = TRUE;
  718.                         else {
  719.                                 wait = FALSE;
  720.                                 s = ins_ptr(p);
  721.                                 link(last_ins_ptr(r)) = s;
  722.                                 s = last_ins_ptr(r);
  723.                                 if (best_ins_ptr(r) == p) {
  724.                                         if (type(r) == SPLIT_UP &&
  725.                                                 broken_ins(r) == p &&
  726.                                                 broken_ptr(r) != NULL) {
  727.                                                 while (link(s) != broken_ptr(r))
  728.                                                         s = link(s);
  729.                                                 split_top_skip = split_top_ptr(p);
  730.                                                 ins_ptr(p) = prune_page_top(broken_ptr(r));
  731.                                                 if (ins_ptr(p) != NULL) {
  732.                                                         temp_ptr = vpack(ins_ptr(p), NATURAL);
  733.                                                         height(p) = height(temp_ptr) + depth(temp_ptr);
  734.                                                         free_node(temp_ptr, BOX_NODE_SIZE);
  735.                                                         wait = TRUE;
  736.                                                 }
  737.                                                 link(s) = NULL;
  738.                                         }
  739.                                         best_ins_ptr(r) = NULL;
  740.                                         n = qo(subtype(r));
  741.                                         temp_ptr = list_ptr(box(n));
  742.                                         free_node(box(n), BOX_NODE_SIZE);
  743.                                         box(n) = vpack(temp_ptr, NATURAL);
  744.                                 } else {
  745.                                         while (link(s) != NULL)
  746.                                                 s = link(s);
  747.                                         last_ins_ptr(r) = s;
  748.                                 }
  749.                         }
  750.                         link(prev_p) = link(p);
  751.                         link(p) = NULL;
  752.                         if (wait) {
  753.                                 link(q) = p;
  754.                                 q = p;
  755.                                 incr(insert_penalties);
  756.                         } else {
  757.                                 delete_glue_ref(split_top_ptr(p));
  758.                                 free_node(p, INS_NODE_SIZE);
  759.                         }
  760.                         p = prev_p;
  761.                 } else if (type(p) == MARK_NODE) {
  762.                         if (first_mark == NULL) {
  763.                                 first_mark = mark_ptr(p);
  764.                                 add_token_ref(first_mark);
  765.                         }
  766.                         if (bot_mark != NULL)
  767.                                 delete_token_ref(bot_mark);
  768.                         bot_mark = mark_ptr(p);
  769.                         add_token_ref(bot_mark);
  770.                 }
  771.                 prev_p = p;
  772.                 p = link(prev_p);
  773.         }
  774.         split_top_skip = save_split_top_skip;
  775.         if (p != NULL) {
  776.                 if (link(contrib_head) == NULL) {
  777.                         if (nest_ptr == 0)
  778.                                 tail = page_tail;
  779.                         else contrib_tail = page_tail;
  780.                 }
  781.                 link(page_tail) = link(contrib_head);
  782.                 link(contrib_head) = p;
  783.                 link(prev_p) = NULL;
  784.         }
  785.         save_vbadness = vbadness;
  786.         vbadness = INF_BAD;
  787.         save_vfuzz = vfuzz;
  788.         vfuzz = MAX_DIMEN;
  789.         box(255) = vpackage(link(page_head), best_size, EXACTLY, page_max_depth);
  790.         vbadness = save_vbadness;
  791.         vfuzz = save_vfuzz;
  792.         if (last_glue != MAX_HALFWORD)
  793.                 delete_glue_ref(last_glue);
  794.         start_new_page();
  795.         if (q != hold_head) {
  796.                 link(page_head) = link(hold_head);
  797.                 page_tail = q;
  798.         }
  799.         r = link(page_ins_head);
  800.         while (r != page_ins_head) {
  801.                 q = link(r);
  802.                 free_node(r, PAGE_INS_NODE_SIZE);
  803.                 r = q;
  804.         }
  805.         link(page_ins_head) = page_ins_head;
  806.         if (top_mark != NULL && first_mark == NULL) {
  807.                 first_mark = top_mark;
  808.                 add_token_ref(top_mark);
  809.         }
  810.         if (output_routine != NULL) {
  811.                 if (dead_cycles >= max_dead_cycles) {
  812.                         print_err("Output loop---");
  813.                         print_int(dead_cycles);
  814.                         print(" consecutive dead cycles");
  815.                         help_dead_cycles();
  816.                         error();
  817.                 } else {
  818.                         output_active = TRUE;
  819.                         incr(dead_cycles);
  820.                         push_nest();
  821.                         mode = -VMODE;
  822.                         prev_depth = IGNORE_DEPTH;
  823.                         mode_line = -line;
  824.                         begin_token_list(output_routine, OUTPUT_TEXT);
  825.                         new_save_level(OUTPUT_GROUP);
  826.                         normal_paragraph();
  827.                         scan_left_brace();
  828.                         return;
  829.                 }
  830.         }
  831.         if (link(page_head) != NULL) {
  832.                 if (link(contrib_head) == NULL) {
  833.                         if (nest_ptr == 0) tail = page_tail;
  834.                         else contrib_tail = page_tail;
  835.                 } else link(page_tail) = link(contrib_head);
  836.                 link(contrib_head) = link(page_head);
  837.                 link(page_head) = NULL;
  838.                 page_tail = page_head;
  839.         }
  840.         ship_out(box(255));
  841.         box(255) = NULL;
  842. }
  843.  
  844. /*
  845.  *      Help text
  846.  */
  847.  
  848. help_tut ()
  849. {
  850.         help3("Tut tut: You're trying to \\insert into a",
  851.         "\\box register that now contains an \\hbox.",
  852.         "Proceed, and I'll discard its present contents.");
  853. }
  854.  
  855. help_vsplit_vbox ()
  856. {
  857.         help2("The box you are trying to split is an \\hbox.",
  858.         "I can't split such boxes, so I'll leave it alone.");
  859. }
  860.  
  861. help_inf_shrink_ins ()
  862. {
  863.         help3("The correction glue for page breaking with insertions",
  864.         "must have finite shrinkability. But you may proceed,",
  865.         "since the offensive shrinkability has been made finite.");
  866. }
  867.  
  868. help_inf_shrink_box ()
  869. {
  870.         help4("The box you are \\vsplitting contains some infinitely",
  871.         "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
  872.         "Such glue doesn't belong there; but you can safely proceed,",
  873.         "since the offensive shrinkability has been made finite.");
  874. }
  875.  
  876. help_inf_shrink_page ()
  877. {
  878.         help4("The page about to be output contains some infinitely ",
  879.         "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
  880.         "Such glue doesn't belong there; but you can safely proceed,",
  881.         "since the offensive shrinkability has been made finite.");
  882. }
  883.  
  884. help_box_255 ()
  885. {
  886.         help2("You shouldn't use \\box255 except in \\output routines.",
  887.         "Proceed, and I'll discard its present contents.");
  888. }
  889.  
  890. help_dead_cycles ()
  891. {
  892.         help3("I've concluded that your \\output is awry; it never does a",
  893.         "\\shipout, so I'm shipping \\box255 out myself. Next time",
  894.         "increase \\maxdeadcycles if you want me to be more patient!");
  895. }
  896.